
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include "../common/constants.h"
#include "../topology/topology.h"
#include "../utils/concurrent.h"
#include "dvtable.h"

//这个函数动态创建距离矢量表.
//距离矢量表包含n+1个条目, 其中n是这个节点的邻居数,剩下1个是这个节点本身.
//距离矢量表中的每个条目是一个dv_t结构,它包含一个源节点ID和一个有N个dv_entry_t结构的数组, 其中N是重叠网络中节点总数.
//每个dv_entry_t包含一个目的节点地址和从该源节点到该目的节点的链路代价.
//距离矢量表也在这个函数中初始化.从这个节点到其邻居的链路代价使用提取自topology.dat文件中的直接链路代价初始化.
//其他链路代价被初始化为INFINITE_COST.
//该函数返回动态创建的距离矢量表.

int dvtable_get_nodeIndex(dv_t* dvtable,int node_id)
{
  int dvt_size=topology_getNbrNum()+1;
  int index=0;
  for(int i=0;i<dvt_size;i++)
  {
    if(dvtable[i].nodeID==node_id)
    {
      index=i;
      break;
    }
  }
  return index;
}

dv_t* dvtable_create()
{
  int nbr_num=topology_getNbrNum();
  int node_num=topology_getNodeNum();
  int self_id=topology_getMyNodeID();
  int* nbr_array=topology_getNbrArray();
  int* node_array=topology_getNodeArray();

  int dvt_size=nbr_num+1;
  dv_t* dvt=(dv_t*)calloc(dvt_size,sizeof(dv_t));

  //数组第一个放自己
  int index = 0;
  dvt[index].nodeID=self_id;
  dvt[index].dvEntry = (dv_entry_t*)calloc(node_num,sizeof(dv_entry_t));
  for(int i=0;i<node_num;i++)
  {
    int node_id = node_array[i];
    dvt[index].dvEntry[i].nodeID=node_id;
    dvt[index].dvEntry[i].cost=topology_getCost(self_id,node_id);
  }

  //后面的放邻居
  for(int i=1;i<dvt_size;i++)
  {
    dvt[i].nodeID = nbr_array[i-1];//邻居数组是从0开始
    dvt[i].dvEntry = (dv_entry_t*)calloc(node_num,sizeof(dv_entry_t));
    for(int j=0;j<node_num;j++)
    {
      dvt[i].dvEntry[j].nodeID=node_array[j];
      dvt[i].dvEntry[j].cost=INFINITE_COST;
    }
  }
  
  free(nbr_array);
  free(node_array);
  return dvt;
}

//这个函数删除距离矢量表.
//它释放所有为距离矢量表动态分配的内存.
void dvtable_destroy(dv_t* dvtable)
{
  int nbr_num=topology_getNbrNum();
  int dvt_size=nbr_num+1;
  for(int i=0;i<dvt_size;i++)
  {
    free(dvtable[i].dvEntry);
  }
  free(dvtable);
}

//这个函数设置距离矢量表中2个节点之间的链路代价.
//如果这2个节点在表中发现了,并且链路代价也被成功设置了,就返回1,否则返回-1.
int dvtable_setcost(dv_t* dvtable,int fromNodeID,int toNodeID, unsigned int cost)
{
  int from_index=dvtable_get_nodeIndex(dvtable,fromNodeID);
  int node_num=topology_getNodeNum();

  for(int i=0;i<node_num;i++)
  {
    if(dvtable[from_index].dvEntry[i].nodeID==toNodeID)
    {
      dvtable[from_index].dvEntry[i].cost=cost;
      break;
    }
  }

  return 1;
}

//这个函数返回距离矢量表中2个节点之间的链路代价.
//如果这2个节点在表中发现了,就返回链路代价,否则返回INFINITE_COST.
unsigned int dvtable_getcost(dv_t* dvtable, int fromNodeID, int toNodeID)
{
  int nbr_num=topology_getNbrNum();
  int node_num=topology_getNodeNum();
  int dvt_size=nbr_num+1;

  for(int i=0;i<dvt_size;i++)
    for(int j=0;j<node_num;j++)
      if(dvtable[i].nodeID==fromNodeID && 
         dvtable[i].dvEntry[j].nodeID==toNodeID)
        return dvtable[i].dvEntry[j].cost;

  return INFINITE_COST;
}

//这个函数打印距离矢量表的内容.
void dvtable_print(dv_t* dvtable)
{
  int dvt_size = topology_getNbrNum()+1;
  int node_num=topology_getNodeNum();
  
  concurrent_printf("**********Distance Vector Table**********\n");
  for(int i=0;i<dvt_size;i++)
  {
    concurrent_printf("%d ",dvtable[i].nodeID);
    for(int j=0;j<node_num;j++)
    {
      concurrent_printf("(id:%d,cost:%d) ",dvtable[i].dvEntry[j].nodeID,dvtable[i].dvEntry[j].cost);
    }
    concurrent_printf("\n");
  }
  concurrent_printf("**********Distance Vector Table**********\n");
}
